import win32com.client
import pythoncom

app = None
""" 
The main iTunes COM object. Examples::
    itunes.app.PlayPause()
    itunes.app.CurrentTrack.Name
    itunes.app.NextTrack()
"""

_events = None
""" A class which handles iTunes events. """

track_handler = None
""" 
A function which is called when the track is changed, e.g.::
    def foo(track):
        print track.name
   
    itunes.exit_handler = foo
"""

exit_handler = None
"""
A function which is called when the user is attempting to quit iTunes, 
in order to properly cleanup the application and close the connection.
"""

event_success = False
"""
Will be set to True on the first sign that iTunes events are being received
successfully. This is due to a bug: occasionally, events will not be received
from iTunes (fixed by restarting iTunes). This mainly happens when an application
does not close() the connection successfully.
"""

def com2track(track):
    """
    Returns a Track object representing some IITTrack information, in order
    to release the COM object.  
    """
    if track is None:
        return None
    t = Track()
    t.name = track.Name
    t.artist = track.Artist
    t.album = track.Album
    t.year = track.Year
    t.rating = track.Rating
    del track
    return t

class Track:
    """ A Track wrapper. """
    def __init__(self):
        self.name = None
        self.artist = None
        self.album = None
        self.year = None
        self.rating = None
        
    def __eq__(self, track):
        if isinstance(track, Track):
            return self.name == track.name \
                and self.artist == track.artist \
                and self.album == track.album \
                and self.year == track.year
        return NotImplemented
    
    def __ne__(self, track):
        result = self.__eq__(track)
        if result is NotImplemented:
            return result
        return not result
    
    def __str__(self):
        return self.name+" by "+self.artist
        
class EventHandler:   
    """
    An event handler to catch iTunes events.
    """ 
    def OnPlayerPlayEvent(self, track):
        global event_success
        if event_success is False:
            print "Event success!"
        event_success = True
        if track_handler is not None:
            track_handler.__call__(com2track(app.CurrentTrack))
    def OnPlayerStopEvent(self, track):
        global event_success
        if event_success is False:
            print "Event success!"
        event_success = True
    def OnAboutToPromptUserToQuitEvent(self):
        print "Cleaning up..."
        if exit_handler is not None:
            exit_handler.__call__()

def close():
    """
    Closes the connection to iTunes COM. This should be called
    when the Python application exits, or when iTunes is about
    to prompt the user to quit (using exit_handler). If successful,
    this method will return 0.
    
    @return: number of interfaces still connected to iTunes COM
    """
    global app, _events
    #close and release the COM objects if we haven't already
    if _events:
        _events.close()
        _events = None
        app = None
        pythoncom.CoFreeUnusedLibraries()
        pythoncom.CoUninitialize()
        #if > 0, iTunes will not exit gracefully
        return pythoncom._GetInterfaceCount()
    
def connect():
    """
    Connects to the iTunes COM, opening iTunes if it isn't 
    already running. This must be called in order to interact
    with iTunes.
    """
    global app, _events
    
    #This would bring iTunes to the front, but it
    #seems buggy with the event handling
    #subprocess.call("C:\Program Files\iTunes\iTunes.exe")
    
    #connect to COM
    pythoncom.CoInitialize()
    app = win32com.client.gencache.EnsureDispatch("iTunes.Application") 
    _events = win32com.client.WithEvents(app, EventHandler)